package com.kedacom.ldap.demo;

import java.util.List;

import javax.naming.Name;

import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;

public class PersonDaoImpl implements PersonDao {
	private LdapTemplate ldapTemplate;

	public void setLdapTemplate(LdapTemplate ldapTemplate) {
		this.ldapTemplate = ldapTemplate;
	}

	public void create(Person person) {
		DirContextAdapter context = new DirContextAdapter(buildDn(person));
		mapToContext(person, context);
		ldapTemplate.bind(context);
	}

	public void update(Person person) {
		Name dn = buildDn(person);
		DirContextOperations context = ldapTemplate.lookupContext(dn);
		mapToContext(person, context);
		ldapTemplate.modifyAttributes(context);
	}

	public void delete(Person person) {
		ldapTemplate.unbind(buildDn(person));
	}

	public Person findByPrimaryKey(String name, String mail) {
		Name dn = buildDn(name);
		return (Person) ldapTemplate.lookup(dn, getContextMapper());
	}

	public List<Person> findByName(String name) {
		AndFilter filter = new AndFilter();
		filter.and(new EqualsFilter("objectclass", "inetOrgPerson")).and(new WhitespaceWildcardsFilter("cn", name));
		return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
	}

	public List<Person> findAll() {
		EqualsFilter filter = new EqualsFilter("objectclass", "inetOrgPerson");
		return ldapTemplate.search(DistinguishedName.EMPTY_PATH, filter.encode(), getContextMapper());
	}

	protected ContextMapper getContextMapper() {
		return (ContextMapper) new PersonContextMapper();
	}

	protected Name buildDn(Person person) {
		return buildDn(person.getName());
	}

	protected Name buildDn(String name) {
		DistinguishedName dn = new DistinguishedName();
		dn.add("cn", name);
		//dn.add("sn", name);
		return dn;
	}

	protected void mapToContext(Person person, DirContextOperations context) {
		context.setAttributeValues("objectclass", new String[] { "top", "inetOrgPerson" });
		context.setAttributeValue("cn", person.getName());
		context.setAttributeValue("sn", person.getName());
		context.setAttributeValue("mail", person.getMail());
	}

	private static class PersonContextMapper extends AbstractContextMapper {
		public Object doMapFromContext(DirContextOperations context) {
			Person person = new Person();
			person.setName(context.getStringAttribute("cn"));
			person.setMail(context.getStringAttribute("mail"));
			return person;
		}
	}
}
